#ifndef EXCHANGE_IO_PARAMETER_H
#define EXCHANGE_IO_PARAMETER_H

#pragma once

#include <list>
#include <vector>
namespace  AMCAX::Exchange {

/// @ingroup Parameter
/// @brief This class is used to define the parameters for the exchange.
/// 
class ExchangeParameter{
public:
    virtual ~ExchangeParameter() = default ;
} ;

/// @ingroup Parameter
/// @brief The precision control information for GLTF, include linear and angle precision, etc
/// 
class GltfOutputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new Gltf Output Parameter object
    /// 
    /// @param[in] linearDeflection : The linear precision of the output model.
    /// @param[in] angleDeflection : The angle precision of the output model.
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    GltfOutputParameter(double linearDeflection, double angleDeflection)
    :linearDeflection_(linearDeflection) ,
    angleDeflection_(angleDeflection) 
    {} ;
    ~GltfOutputParameter() {} ;
    /// @brief Get the Linear Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The linear precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetLinearDeflection() const { return linearDeflection_ ; }
    /// @brief Get the angle Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The angle precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetAngleDeflection() const { return angleDeflection_ ; }
private:
    double linearDeflection_ ;
    double angleDeflection_ ;
} ;

/// @ingroup Parameter
/// @brief The precision control information for OBJ, include linear and angle precision, etc
/// 
class ObjOutputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new OBJ Output Parameter object
    /// 
    /// @param[in] linearDeflection : The linear precision of the output model.
    /// @param[in] angleDeflection : The angle precision of the output model.
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    ObjOutputParameter(double linearDeflection, double angleDeflection)
    :linearDeflection_(linearDeflection) ,
    angleDeflection_(angleDeflection) 
    {} ; ;
    ~ObjOutputParameter() {} ;
    /// @brief Get the Linear Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The linear precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetLinearDeflection() const { return linearDeflection_ ; }
    /// @brief Get the angle Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The angle precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetAngleDeflection() const { return angleDeflection_ ; }
private:
    double linearDeflection_ ;// range 0.001~1
    double angleDeflection_ ;
} ;

/// @ingroup Parameter
/// @brief The precision control information for OBJ, include linear and angle precision, etc
/// 
class StlOutputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new STL Output Parameter object
    /// 
    /// @param[in] linearDeflection : The linear precision of the output model.
    /// @param[in] angleDeflection : The angle precision of the output model.
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    StlOutputParameter(double linearDeflection, double angleDeflection)
    :linearDeflection_(linearDeflection) ,
    angleDeflection_(angleDeflection) 
    {} ;
    ~StlOutputParameter() {} ;
    /// @brief Get the Linear Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The linear precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetLinearDeflection() const { return linearDeflection_ ; }
    /// @brief Get the angle Deflection object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return  The angle precision of the output model.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    double GetAngleDeflection() const { return angleDeflection_ ; }
private:
    double linearDeflection_ ;// range 0.001~1
    double angleDeflection_ ;
} ;

/// @ingroup Parameter
/// @brief Control the output of step file.
/// 
enum class STEP_WRITE_TYPE
{
    WRITE_ALL_2_ONE,
    WRITE_ALL_NON_EMPTY,
    WRITE_ALL
} ;

/// @ingroup Parameter
/// @brief Control the output of step file.
/// 
class StepOutputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new Step Output Parameter object
    /// 
    /// @param[in] writeType: Write once, non-empty write ,write by structure and other methods.
    /// @param[out] NONE
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    StepOutputParameter(STEP_WRITE_TYPE writeType)
    :writeType_(writeType) 
    {} ;
    /// @brief Get the Write Type object
    /// 
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return STEP_WRITE_TYPE: Write once, non-empty write ,write by structure and other methods.
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    STEP_WRITE_TYPE GetWriteType(){
        return writeType_ ;
    } ;
private:
    STEP_WRITE_TYPE writeType_ ;
} ;

/// @ingroup Parameter
/// @brief Control the input of dxf file.
/// 
class DxfInputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new Dxf Input Parameter object
    /// 
    /// @param[in] layer:  layer name of dxf file.
    /// @param[out] NONE
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    DxfInputParameter(const std::vector<std::string> layer)
    : layers_(layer)
    {} ;

    const std::vector<std::string> &GetLayers() const { return layers_ ; }
private: 
    const std::vector<std::string> layers_ ;
} ;

/// @ingroup Parameter
/// @brief the output facet type.
/// 
enum class INTEROP_META_FACET_TYPE
{
    FACET_TYPE_TRIANGLE = 0,
    FACET_TYPE_QUAD
} ;

/// @brief Control the input parameters of InterOp exchange.
/// 
class InterOpInputParameter : public ExchangeParameter
{
public:
    /// @brief Construct a new InterOp exchange Input Parameter object
    /// @param[in] facetType: output meta facet type. Default is triangle.
    /// @param[in] maxEdgeLength: The max edge length of the meta facet edge. Default is 0.0, means this option is ignored.
    /// @return NONE
    /// @retval NONE
    /// @note NONE
    /// @see NONE
    InterOpInputParameter(INTEROP_META_FACET_TYPE facetType = INTEROP_META_FACET_TYPE::FACET_TYPE_TRIANGLE, double maxEdgeLength = 0.0)
    : facetType_(facetType), maxEdgeLength_(maxEdgeLength) 
    {} ;

    /// @brief Get the meta output facet type.
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The meta output facet type.
    /// @note The facet type is used to control the output meta facet type. The default value is triangle.
    const INTEROP_META_FACET_TYPE &GetFacetType() const { return facetType_; }

    /// @brief Get the meta max edge length.
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The meta max edge length.
    /// @note The max edge length is used to control the output meta facet edge length. The default value is 0.0, means this option is ignored.
    double GetMaxEdgeLength() const { return maxEdgeLength_; }

private: 
    const INTEROP_META_FACET_TYPE facetType_ ;
    double maxEdgeLength_;
};

/// @brief The result parameters of InterOp exchange.
///
class InterOpResultParameter : public ExchangeParameter
{
public:
    /// @brief The 3D point structure.
    ///
    /// @param[in] x: The x coordinate of the point.
    /// @param[in] y: The y coordinate of the point.
    /// @param[in] z: The z coordinate of the point.
    struct Point3D
    {
        double x;
        double y;
        double z;
    };
public:

    /// @brief Default construct a new InterOpResultParameter object
    ///
    InterOpResultParameter() = default;

    /// @brief Get the volume from the result parameter
    ///
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The volume of the result parameter.
    double GetVolume() const { return volume_; }

    /// @brief Set the volume to the result parameter
    ///
    /// @param[in] volume: The volume to set.
    /// @param[out] NONE
    /// @return NONE
    void SetVolume(double volume) { volume_ = volume; }

    /// @brief Get the area from the result parameter
    ///
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The area of the result parameter.
    double GetArea() const { return area_; }

    /// @brief Set the area to the result parameter
    ///
    /// @param[in] area: The area to set.
    /// @param[out] NONE
    /// @return NONE
    void SetArea(double area) { area_ = area; }

    /// @brief Get the vertexes from the result parameter
    ///
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The vertexes of the result parameter.
    std::list<Point3D> GetVertexes() const { return vertexes_; }

    /// @brief Set the vertexes to the result parameter
    ///
    /// @param[in] vertexes: The vertexes to set.
    /// @param[out] NONE
    /// @return NONE
    /// @note The vertexes are stored as a list of Point3D structures.
    void SetVertexes(const std::list<Point3D> &vertexes) { vertexes_ = vertexes; }

    /// @brief Get the triangles from the result parameter
    ///
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The triangles of the result parameter.
    /// @note The triangles are stored as a list of lists of Point3D structures.
    std::list<std::list<Point3D>> GetTriangles() const { return triangles_; }

    /// @brief Set the triangles to the result parameter
    ///
    /// @param[in] triangles: The triangles to set.
    /// @param[out] NONE
    /// @return NONE
    /// @note The triangles are stored as a list of lists of Point3D structures.
    void SetTriangles(const std::list<std::list<Point3D>> &triangles) { triangles_ = triangles; }

    /// @brief Get the topology JSON file path from the result parameter
    ///
    /// @param[in] NONE
    /// @param[out] NONE
    /// @return The topology JSON file path of the result parameter.
    /// @note The topology JSON file path is used to store the topology information of the result parameter.
    std::string GetTopologyJsonFilePath() const { return topologyJsonFilePath_; }

    /// @brief Set the topology JSON file path to the result parameter
    ///
    /// @param[in] topologyJsonFilePath: The topology JSON file path to set.
    /// @param[out] NONE
    /// @return NONE
    /// @note The topology JSON file path is used to store the topology information of the result parameter.
    void SetTopologyJsonFilePath(const std::string &topologyJsonFilePath) { topologyJsonFilePath_ = topologyJsonFilePath; }

private:
    double volume_;
    double area_;
    std::list<Point3D> vertexes_;
    std::list<std::list<Point3D>> triangles_;
    std::string topologyJsonFilePath_;
};
};

#endif // EXCHANGE_IO_PARAMETER_H